package com.zzyl.nursing.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.*;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.core.domain.AjaxResult;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.common.utils.uuid.UUID;
import com.zzyl.nursing.domain.Device;
import com.zzyl.nursing.dto.DeviceDto;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.service.IDeviceService;
import com.zzyl.nursing.vo.DeviceDetailVo;
import com.zzyl.nursing.vo.ProductVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;

/**
 * 设备信息Service业务层处理
 *
 * @author alexis
 * @date 2025-06-05
 */
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService {

    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private IoTDAClient iotClient;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 查询设备信息列表
     *
     * @param device 设备信息
     * @return 设备信息
     */
    @Override
    public List<Device> selectDeviceList(Device device) {
        return deviceMapper.selectDeviceList(device);
    }

    /**
     * 同步产品列表
     */
    @Override
    public void syncProductList() {
        //请求参数
        ListProductsRequest listProductsRequest = new ListProductsRequest();
        //设置条数
        listProductsRequest.setLimit(50);
        //发起请求
        ListProductsResponse response = iotClient.listProducts(listProductsRequest);
        if (response.getHttpStatusCode() != 200) {
            throw new BaseException("物联网接口 - 查询产品，同步失败");
        }
        //存储到redis
        redisTemplate.opsForValue()
                     .set(CacheConstants.IOT_ALL_PRODUCT_LIST, JSONUtil.toJsonStr(response.getProducts()));
    }

    /**
     * 查询所有产品
     *
     * @return 产品列表
     */
    @Override
    public List<ProductVo> allProduct() {
        // 1. 从redis中获取产品列表
        Object object = redisTemplate.opsForValue().get(CacheConstants.IOT_ALL_PRODUCT_LIST);
        // 2.解析并返回
        if (object != null) {
            return JSONUtil.toList(object.toString(), ProductVo.class);
        }
        // 3.如果没有，则返回空集合
        return List.of();
    }

    /**
     * 注册设备
     *
     * @param deviceDto 设备信息
     */
    @Override
    public void register(DeviceDto deviceDto) {
        // 1.判断设备名称是否重复
        Long count = lambdaQuery().eq(Device::getDeviceName, deviceDto.getDeviceName()).count();
        if (count > 0) {
            throw new BaseException("设备名称重复");
        }

        // 2.判断设备标识是否重复
        count = lambdaQuery().eq(Device::getNodeId, deviceDto.getNodeId()).count();
        if (count > 0) {
            throw new BaseException("设备标识重复");
        }

        // 如果为随身设备,设置物理位置类型为-1
        if (deviceDto.getLocationType() == 0) {
            deviceDto.setPhysicalLocationType(-1);
        }

        // 3.判断同一位置是否绑定了相同产品
        count = lambdaQuery().eq(Device::getBindingLocation, deviceDto.getBindingLocation())
                             .eq(Device::getProductKey, deviceDto.getProductKey())
                             .eq(Device::getLocationType, deviceDto.getLocationType())
                             .eq(Device::getPhysicalLocationType, deviceDto.getPhysicalLocationType())
                             .count();
        if (count > 0) {
            throw new BaseException("同一位置已绑定相同产品");
        }

        // 4.注册设备到华为云IOT
        // 随机生成密钥
        String secret = UUID.randomUUID().toString().replaceAll("-", "");
        AddDeviceRequest addDeviceRequest = new AddDeviceRequest();
        AddDevice addDevice = new AddDevice();
        addDevice.withDeviceName(deviceDto.getDeviceName())
                 .withNodeId(deviceDto.getNodeId())
                 .withProductId(deviceDto.getProductKey())
                 .withAuthInfo(new AuthInfo().withSecret(secret));

        addDeviceRequest.withBody(addDevice);

        AddDeviceResponse addDeviceResponse = iotClient.addDevice(addDeviceRequest);
        if (addDeviceResponse.getHttpStatusCode() != 201) {
            throw new BaseException("物联网接口 - 注册设备失败");
        }

        // 5.保存设备信息到数据库
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        device.setSecret(secret);
        device.setIotId(addDeviceResponse.getDeviceId());
        save(device);
    }

    /**
     * 查询设备详情
     *
     * @param iotId 设备id
     * @return 设备详情
     */
    @Override
    public DeviceDetailVo queryDeviceDetail(String iotId) {
        // 1.从数据库中查询设备详情
        Device device = lambdaQuery().eq(Device::getIotId, iotId).one();
        if (ObjectUtil.isEmpty(device)) {
            throw new BaseException("设备不存在");
        }

        // 2.从华为云IOT中查询设备详情
        ShowDeviceRequest showDeviceRequest = new ShowDeviceRequest();
        showDeviceRequest.setDeviceId(iotId);
        ShowDeviceResponse showDeviceResponse;
        try {
            showDeviceResponse = iotClient.showDevice(showDeviceRequest);
        }
        catch (Exception e) {
            log.error("物联网接口 - 获取设备详情失败");
            throw new BaseException("物联网接口 - 查询设备详情失败");
        }

        // 3.组装并返回设备详情
        DeviceDetailVo deviceDetailVo = BeanUtil.toBean(device, DeviceDetailVo.class);
        deviceDetailVo.setDeviceStatus(showDeviceResponse.getStatus());
        String activeTimeStr = showDeviceResponse.getActiveTime();
        if (StringUtils.isNotEmpty(activeTimeStr)) {
            LocalDateTime activeTime = DateUtils.convertActiveTime(activeTimeStr, DatePattern.UTC_MS_PATTERN);
            deviceDetailVo.setActiveTime(activeTime);
        }

        return deviceDetailVo;
    }


    /**
     * 修改设备
     *
     * @param deviceDto 设备信息
     */
    @Override
    public void updateDevice(DeviceDto deviceDto) {
        // 判断设备名称是否重复
        Long count = lambdaQuery().eq(Device::getDeviceName, deviceDto.getDeviceName())
                                  .ne(Device::getIotId, deviceDto.getIotId())
                                  .count();
        if (count > 0) {
            throw new BaseException("设备名称重复");
        }

        // 如果为随身设备,设置物理位置类型为-1
        if (deviceDto.getLocationType() == 0) {
            deviceDto.setPhysicalLocationType(-1);
        }

        // 判断设备在同一位置是否已绑定相同产品
        count = lambdaQuery().eq(Device::getBindingLocation, deviceDto.getBindingLocation())
                             .eq(Device::getProductKey, deviceDto.getProductKey())
                             .eq(Device::getLocationType, deviceDto.getLocationType())
                             .eq(Device::getPhysicalLocationType, deviceDto.getPhysicalLocationType())
                             .ne(Device::getIotId, deviceDto.getIotId())
                             .count();
        if (count > 0) {
            throw new BaseException("同一位置已绑定相同产品");
        }

        // 1.更新华为云IOT设备信息
        UpdateDeviceRequest updateDeviceRequest = new UpdateDeviceRequest();
        UpdateDevice updateDevice = new UpdateDevice();
        updateDevice.withDeviceName(deviceDto.getDeviceName());
        updateDeviceRequest.withDeviceId(deviceDto.getIotId())
                           .withBody(updateDevice);
        try {
            iotClient.updateDevice(updateDeviceRequest);
        }
        catch (Exception e) {
            log.error("物联网接口 - 修改设备失败", e);
            throw new BaseException("物联网接口 - 修改设备失败");
        }

        // 2.更新数据库设备信息
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        updateById(device);
    }

    /**
     * 删除设备
     *
     * @param iotId 设备id
     */
    @Override
    public void removeDevice(String iotId) {
        // 1.从华为云IOT中删除设备
        DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
        deleteDeviceRequest.setDeviceId(iotId);
        try {
            iotClient.deleteDevice(deleteDeviceRequest);
        }
        catch (Exception e) {
            log.error("物联网接口 - 删除设备失败", e);
            throw new BaseException("物联网接口 - 删除设备失败");
        }

        // 2.删除数据库设备信息
        lambdaUpdate().eq(Device::getIotId, iotId)
                      .remove();
    }

    /**
     * 查询设备上报数据
     *
     * @param iotId 设备id
     * @return 设备服务属性
     */
    @Override
    public AjaxResult queryServiceProperties(String iotId) {
        ShowDeviceShadowRequest request = new ShowDeviceShadowRequest();
        request.setDeviceId(iotId);
        ShowDeviceShadowResponse response = iotClient.showDeviceShadow(request);
        if (response.getHttpStatusCode() != 200) {
            throw new BaseException("物联网接口 - 查询设备上报数据，调用失败");
        }
        List<DeviceShadowData> shadow = response.getShadow();
        if (CollUtil.isEmpty(shadow)) {
            List<Object> emptyList = Collections.emptyList();
            return AjaxResult.success(emptyList);
        }
        //返回数据
        JSONObject jsonObject = JSONUtil.parseObj(shadow.get(0).getReported().getProperties());

        List<Map<String, Object>> list = new ArrayList<>();

        //日期时区转换
        LocalDateTime eventTime = DateUtils.convertActiveTime(
                shadow.get(0).getReported().getEventTime(), "yyyyMMdd'T'HHmmss'Z'");

        jsonObject.forEach((k, v) -> {
            Map<String, Object> map = new HashMap<>();
            map.put("functionId", k);
            map.put("value", v);
            map.put("eventTime", eventTime);
            list.add(map);
        });

        return AjaxResult.success(list);
    }

    /**
     * 查询产品信息
     *
     * @param productKey 产品key
     * @return 产品信息
     */
    @Override
    public AjaxResult queryProduct(String productKey) {
        ShowProductRequest request = new ShowProductRequest();
        request.setProductId(productKey);
        ShowProductResponse response = null;
        try {
            response = iotClient.showProduct(request);
        }
        catch (Exception e) {
            throw new BaseException("查询产品详情失败！");
        }
        List<ServiceCapability> serviceCapabilities = response.getServiceCapabilities();
        if (CollUtil.isEmpty(serviceCapabilities)) {
            return AjaxResult.success(Collections.emptyList());
        }
        return AjaxResult.success(serviceCapabilities);
    }

}
